package cas.ihep.pwa.evtgen;

import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.OneArgFunction;
import org.luaj.vm2.lib.ThreeArgFunction;
import org.luaj.vm2.lib.TwoArgFunction;
import org.luaj.vm2.lib.VarArgFunction;

import javax.script.*;
import java.io.FileReader;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class EvtPDL implements Serializable {

    private int nentries;
    private int firstAlias;
    private ArrayList<EvtPartProp> partlist;
    private HashMap<String,Integer> particleNameLookup;

    public int getId(String name){
        if (particleNameLookup.containsKey(name)){
            int id=particleNameLookup.get(name);
            return partlist.get(id).id.getId();
        }
        return -1;
    }

    public EvtId getEvtId(String name){
        if(particleNameLookup.containsKey(name)){
            int id=particleNameLookup.get(name);
            return partlist.get(id).id;
        }
        return EvtId.defaultId;
    }

    public double getMeanMass(EvtId id){
        return partlist.get(id.getId()).lineShape.getMass();
    }

    public double getMeanMass(int id){
        return partlist.get(id).lineShape.getMass();
    }

    public double getMass(EvtId id){
        return partlist.get(id.getId()).lineShape.rollMass();
    }

    public double getMass(int id){
        return partlist.get(id).lineShape.rollMass();
    }

    public double getMaxMass(EvtId id){
        return partlist.get(id.getId()).lineShape.getMassMax();
    }

    public double getMaxMass(int id){
        return partlist.get(id).lineShape.getMassMax();
    }

    public double getMinMass(EvtId id){
        return partlist.get(id.getId()).lineShape.getMassMin();
    }

    public double getMinMass(int id){
        return partlist.get(id).lineShape.getMassMin();
    }

    public double getMaxRange(EvtId id){
        return partlist.get(id.getId()).lineShape.getMaxRange();
    }

    public double getMaxRange(int id){
        return partlist.get(id).lineShape.getMaxRange();
    }

    public double getWidth(EvtId id){
        return partlist.get(id.getId()).lineShape.getWidth();
    }

    public double getWidth(int id){
        return partlist.get(id).lineShape.getWidth();
    }

    public EvtSpinType.SpinType getSpinType(EvtId id){
        return partlist.get(id.getId()).spintype;
    }

    public EvtSpinType.SpinType getSpinType(int id){
        return partlist.get(id).spintype;
    }

    public String getName(EvtId id){
        return partlist.get(id.getId()).name;
    }

    public String getName(int id){
        return partlist.get(id).name;
    }

    public double getCtau(EvtId id){
        return partlist.get(id.getId()).ctau;
    }

    public double getCtau(int id){
        return partlist.get(id).ctau;
    }

    public String getLStype(EvtId id){
        return partlist.get(id.getId()).lstype;
    }

    public String getLStype(int id){
        return partlist.get(id).lstype;
    }

    public List<Double> getVpars(EvtId id){
        return partlist.get(id.getId()).vpars;
    }

    public List<Double> getVpars(int id){
        return partlist.get(id).vpars;
    }

    public double[] basicGetVpars(int id){
        EvtPartProp prop=partlist.get(id);
        int sz=prop.vpars.size();
        double ret[]=new double[sz];
        for(int i=0;i<sz;i++){
            ret[i]=prop.vpars.get(i);
        }
        return ret;
    }

    public List<Double> getVRes(EvtId id){
        return partlist.get(id.getId()).vres;
    }

    public List<Double> getVRes(int id){
        return partlist.get(id).vres;
    }

    public double[] basicGetVRes(int id){
        EvtPartProp prop=partlist.get(id);
        int sz=prop.vres.size();
        double ret[]=new double[sz];
        for(int i=0;i<sz;i++){
            ret[i]=prop.vres.get(i);
        }
        return ret;
    }

    public List<String> getVstrs(EvtId id){
        return partlist.get(id.getId()).vstrs;
    }

    public List<String> getVstrs(int id){
        return partlist.get(id).vstrs;
    }

    public void reSetMass(EvtId id,double val){
        partlist.get(id.getId()).lineShape.reSetMass(val);
    }

    public void reSetMass(int id,double val){
        partlist.get(id).lineShape.reSetMass(val);
    }

    public void setLStype(EvtId id,String str){
        partlist.get(id.getId()).lstype=str;
    }

    public void setLStype(int id,String str){
        partlist.get(id).lstype=str;
    }

    public void reSetWidth(EvtId id,double val){
        partlist.get(id.getId()).lineShape.reSetWidth(val);
    }

    public void reSetWidth(int id,double val){
        partlist.get(id).lineShape.reSetWidth(val);
    }

    public void reSetMaxMass(EvtId id,double val){
        partlist.get(id.getId()).lineShape.reSetMassMax(val);
    }

    public void reSetMaxMass(int id,double val){
        partlist.get(id).lineShape.reSetMassMax(val);
    }

    public void reSetMinMass(EvtId id,double val){
        partlist.get(id.getId()).lineShape.reSetMassMin(val);
    }

    public void reSetMinMass(int id,double val){
        partlist.get(id).lineShape.reSetMassMin(val);
    }

    public void setVpars(EvtId id,List<Double> vals){
        List<Double> srcs=partlist.get(id.getId()).vpars;
        srcs.clear();
        srcs.addAll(vals);
    }

    public void setVpars(int id,List<Double> vals){
        List<Double> srcs=partlist.get(id).vpars;
        srcs.clear();
        srcs.addAll(vals);
    }

    public void setVRes(EvtId id,List<Double> vals){
        List<Double> srcs=partlist.get(id.getId()).vres;
        srcs.clear();
        srcs.addAll(vals);
    }

    public void setVRes(int id, List<Double> vals){
        List<Double> srcs=partlist.get(id).vres;
        srcs.clear();
        srcs.addAll(vals);
    }

    public void setVstrs(EvtId id,List<String> vals){
        List<String> srcs=partlist.get(id.getId()).vstrs;
        srcs.clear();
        srcs.addAll(vals);
    }

    public void setVstrs(int id,List<String> vals){
        List<String> srcs=partlist.get(id).vstrs;
        srcs.clear();
        srcs.addAll(vals);
    }

    public EvtPDL(String fname,String decayfname,String userdecay)throws IOException,ScriptException{
        nentries=0;
        firstAlias=999999;
        partlist=new ArrayList<>();
        particleNameLookup=new HashMap<>();
        ScriptEngineManager sem = new ScriptEngineManager();
        ScriptEngine e = sem.getEngineByName("luaj");
        ArrayList<EvtModelAlias> aliases=new ArrayList<>();
        EvtModel model=new EvtModel(this);
        ArrayList<EvtParticleDecayList> evtdecaylist=new ArrayList<>();
        HashMap<String,String> symtable=new HashMap<>();
        readPDT(e,fname);
        readDecay(e, decayfname,aliases,symtable,evtdecaylist,model);
        readDecay(e,userdecay,aliases,symtable,evtdecaylist,model);
    }

    private void readPDT(ScriptEngine e,String filename)throws IOException,ScriptException{
        CompiledScript cs=((Compilable)e).compile(new FileReader(filename));
        Bindings bd=new SimpleBindings();
        bd.put("pdtadd", new OneArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue) {
                return pdtadd(luaValue);
            }
        });
        bd.put("pdtsets", new OneArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue) {
                return LuaValue.NIL;
            }
        });
        cs.eval(bd);
    }

    private LuaValue Particle(LuaValue name,LuaValue newMass,LuaValue newWidth){
        if(name.isstring() && newMass.isnumber() && (newWidth.isnumber() || newWidth.isnil())){
            String namestr=name.tojstring();
            double newMassVal=newMass.todouble();
            int id=getId(namestr);
            double newWidthVal=newWidth.isnumber()?newWidth.todouble():getMeanMass(id);
            reSetMass(id,newMassVal);
            reSetWidth(id,newWidthVal);
            return LuaValue.NIL;
        }
        return LuaValue.error("Invalid type of parameters");
    }

    private LuaValue Vparameters(LuaValue name,LuaValue vpars){
        if(name.isstring() && vpars.istable()){
            LuaTable tvpars=(LuaTable)vpars;
            int sz=tvpars.keyCount();
            ArrayList<Double> vparslist=new ArrayList<>();
            for(int i=0;i<sz;i++){
                LuaValue ele=tvpars.get(i+1);
                if (!ele.isnumber()){
                    return LuaValue.error("Invalid type of parameters");
                }
                vparslist.add(ele.todouble());
            }
            setVpars(getId(name.tojstring()),vparslist);
            return LuaValue.NIL;
        }
        return LuaValue.error("Invalid type of parameters");
    }

    private LuaValue Vstrings(LuaValue name,LuaValue table){
        if(name.isstring() && table.istable()){
            LuaTable vstrs=(LuaTable)table;
            int sz=vstrs.keyCount();
            ArrayList<String> vstrslist=new ArrayList<>();
            for(int i=0;i<sz;i++){
                LuaValue ele=vstrs.get(i+1);
                if(!ele.isstring()){
                    return LuaValue.error("Invalid type of parameter");
                }
                vstrslist.add(ele.tojstring());
            }
            setVstrs(getId(name.tojstring()),vstrslist);
            return LuaValue.NIL;
        }
        return LuaValue.error("Invalid type of parameters");
    }

    private LuaValue changeLStype(LuaValue name,String type){
        if (name.isstring()){
            setLStype(getId(name.tojstring()),type);
            return LuaValue.NIL;
        }
        return LuaValue.error("Invalid type of parameters");
    }

    private LuaValue Define(LuaValue name, LuaValue value, Map<String,String> symtable){
        if (name.isstring() && (value.isnumber() && value.isstring())){
            symtable.put(name.tojstring(),value.tojstring());
            return LuaValue.NIL;
        }
        return LuaValue.error("Invalid type of parameters");
    }

    private LuaValue Alias(LuaValue newname,LuaValue oldname,List<EvtParticleDecayList> decaytable){
        if(newname.isstring() && oldname.isstring()){
            int id=getId(oldname.tojstring());
            if (id==-1){
                throw new RuntimeException();
            }
            alias(id,newname.tojstring());
            reserveCapacity(decaytable,partlist.size());
            return LuaValue.NIL;
        }
        return LuaValue.error("Invalid type of parameters");
    }

    private LuaValue ChargeConj(LuaValue aname,LuaValue abarname){
        if(aname.isstring() && abarname.isstring()){
            EvtId a=getEvtId(aname.tojstring());
            EvtId apar=getEvtId(abarname.tojstring());
            if(EvtId.defaultId.equals(a) || EvtId.defaultId.equals(apar)){
                throw new RuntimeException();
            }
            aliasChgConj(a,apar);
            return LuaValue.NIL;
        }
        return LuaValue.error("Invalid type of parameters");
    }

    private LuaValue ModelAlias(LuaValue aliasname,LuaValue modelname,LuaValue table,List<EvtModelAlias> modelAliasList){
        if(aliasname.isstring() && modelname.isstring() && table.istable()){
            ArrayList<String> modelarglist=new ArrayList<>();
            LuaTable malist=(LuaTable)table;
            int sz=malist.keyCount();
            for(int i=0;i<sz;i++){
                LuaValue val=malist.get(i+1);
                if(!val.isnumber() && !val.isstring()){
                    return LuaValue.error("Invalid type of parameters");
                }
                modelarglist.add(val.tojstring());
            }
            modelAliasList.add(new EvtModelAlias(aliasname.tojstring(),modelname.tojstring(),modelarglist));
            return LuaValue.NIL;
        }
        return LuaValue.error("Invalid type of parameters");
    }

    private void reserveCapacity(List<EvtParticleDecayList> decaytable,int sz){
        int ssz=decaytable.size();
        for(;ssz<sz;ssz++){
            decaytable.add(new EvtParticleDecayList());
        }
    }

    private LuaValue Decay(LuaValue parent,LuaValue table,
                           EvtModel modellist,List<EvtModelAlias> modelAliasList,List<EvtParticleDecayList> decaytable,
                           Map<String,String> symtable){
        if (parent.isstring() && table.istable()){
            reserveCapacity(decaytable,partlist.size());
            double brfrsum=0;
            EvtId ipar=getEvtId(parent.tojstring());
            if (decaytable.get(ipar.getAlias())!=null && decaytable.get(ipar.getAlias()).getNMode()!=0){
                decaytable.get(ipar.getAlias()).removeDecay();
            }
            LuaTable subvalues=(LuaTable)table;
            int sz=subvalues.keyCount();
            for(int i=0;i<sz;i++){
                LuaValue sv=subvalues.get(i+1);
                if(!sv.istable()){
                    return LuaValue.error("Invalid type of parameters");
                }
                LuaTable stable=(LuaTable)sv;
                int nextValue=1;
                LuaValue brfr=stable.get(nextValue++);
                if (!brfr.isnumber()){
                    return LuaValue.error("Invalid type of parameters");
                }
                LuaValue daugs=stable.get(nextValue++);
                LuaTable daugstable=(LuaTable)daugs;
                ArrayList<EvtId> daugpart=new ArrayList<>();
                int daugsz=daugstable.keyCount();
                String firstDaug=daugstable.get(1).tojstring();
                for(int j=0;j<daugsz;j++){
                    daugpart.add(getEvtId(daugstable.get(j+1).tojstring()));
                }
//                boolean isname=daugsz>0 && daugpart.get(0).getId()>=0;
//                int ismodel=modellist.isModel(firstDaug)?1:0;
//                if(!(isname || ismodel!=0)){
//                    int iAlias,__sz=modelAliasList.size();
//                    for(iAlias=0;iAlias<__sz;iAlias++){
//                        if ( modelAliasList.get(iAlias).matchAlias(firstDaug) ) {
//                            ismodel=2;
//                            break;
//                        }
//                    }
//                }
//                if (!(isname || ismodel!=0)){
//                    throw new RuntimeException();
//                }
                LuaValue luamodel=stable.get(nextValue++);
                String model=luamodel.tojstring();
                if("PHOTOS".equals(model)){
                    //System.out.println("PHOTOS");
                    model=stable.get(nextValue++).tojstring();
                }else if("VERBOSE".equals(model)){
                    //System.out.println("VERBOSE");
                    model=stable.get(nextValue++).tojstring();
                }else if("SUMMARY".equals(model)){
                    //System.out.println("SUMMARY");
                    model=stable.get(nextValue++).tojstring();
                }
                int iAlias;
                int foundAnAlias=-1;
                for(iAlias=0;iAlias<modelAliasList.size();iAlias++){
                    if ( modelAliasList.get(iAlias).matchAlias(model) ) {
                        foundAnAlias=iAlias;
                        break;
                    }
                }
                if(foundAnAlias==-1){
                    if(!modellist.isModel(model)){
                        throw new RuntimeException(model + " is not a valid model");
                    }
                }else{
                    model=modelAliasList.get(foundAnAlias).getName();
                }
                LuaTable argtable=(LuaTable)stable.get(nextValue);
                List<String> temp_fcn_new_args;
                if (foundAnAlias==-1){
                    temp_fcn_new_args=new ArrayList<>();
                    int keysize=argtable.keyCount();
                    for(int idx=0;idx<keysize;idx++){
                        temp_fcn_new_args.add(symGet(symtable,argtable.get(idx+1).tojstring()));
                    }
                }else{
                    temp_fcn_new_args=modelAliasList.get(foundAnAlias).getArgList();
                }
                double jbrfr=brfr.todouble();
                brfrsum+=jbrfr;
                EvtDecayBase temp_fcn_new=modellist.getFcn(model);
                double massmin=0;
                temp_fcn_new.saveDecayInfo(ipar,daugsz,daugpart,temp_fcn_new_args.size(),temp_fcn_new_args,model,jbrfr);
                for(EvtId did:daugpart){
                    if(getMinMass(did)>0.0001){
                        massmin+=getMinMass(did);
                    }else{
                        massmin+=getMeanMass(did);
                    }
                }
                decaytable.get(ipar.getAlias()).addMode(temp_fcn_new,brfrsum,massmin);
            }
            decaytable.get(ipar.getAlias()).finish();

            for(int iii=0;iii<partlist.size();iii++){
                int nModTot=decaytable.get(iii).getNMode();
                if(nModTot==0){
                    continue;
                }
                if(getWidth(iii)<0.0000001){
                    continue;
                }
                double minMass=getMaxMass(iii);
                for(int jjj=0;jjj<nModTot;jjj++){
                    double tmass=decaytable.get(iii).getDecay(jjj).getMassMin();
                    if(tmass<minMass){
                        minMass=tmass;
                    }
                }
                if(minMass>getMinMass(iii)){
                    reSetMinMass(iii,minMass);
                }
            }
            return LuaValue.NIL;
        }
        return LuaValue.error("Invalid type of parameters");
    }

    private LuaValue CDecay(LuaValue name,List<EvtParticleDecayList> decaytable){
        if(name.isstring()){
            EvtId ipar=getEvtId(name.tojstring());
            if(ipar.equals(EvtId.defaultId)){
                return LuaValue.error("Unknown particle name");
            }
            EvtId cipar=chargeConj(ipar);
            if(decaytable.get(ipar.getAlias()).getNMode()!=0){
                decaytable.get(ipar.getAlias()).removeDecay();
            }
            decaytable.get(ipar.getAlias()).makeChargeConj(decaytable.get(cipar.getAlias()));
            return LuaValue.NIL;
        }
        return LuaValue.error("Invalid type of parameters");
    }

    private String symGet(Map<String,String> symtable,String key){
        String ret=symtable.get(key);
        if(ret!=null){
            return ret;
        }else{
            return key;
        }
    }

    private LuaValue SetLineShapePW(LuaValue value){
        if (value.istable()){
            LuaTable table=(LuaTable)value;
            EvtId thispart=getEvtId(table.get(1).tojstring());
            EvtId thisD1=getEvtId(table.get(2).tojstring());
            EvtId thisD2=getEvtId(table.get(3).tojstring());
            setPWForDecay(thispart,table.get(4).toint(),thisD1,thisD2);
            return LuaValue.NIL;
        }
        return LuaValue.error("Invalid type of parameters");
    }

    private void readDecay(ScriptEngine e, String filename,
                           final ArrayList<EvtModelAlias> modelAliases,
                           final Map<String,String> symtable,
                           final ArrayList<EvtParticleDecayList> decaytable,
                           final EvtModel modellist)throws IOException,ScriptException{
        CompiledScript cs=((Compilable)e).compile(new FileReader(filename));
        Bindings bd=new SimpleBindings();
        bd.put("Particle", new VarArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue, LuaValue luaValue1) {
                return Particle(luaValue,luaValue1,LuaValue.NIL);
            }

            @Override
            public LuaValue call(LuaValue luaValue, LuaValue luaValue1, LuaValue luaValue2) {
                return Particle(luaValue,luaValue1,luaValue2);
            }
        });
        bd.put("Vparameters", new TwoArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue, LuaValue luaValue1) {
                return Vparameters(luaValue,luaValue1);
            }
        });
        bd.put("Vstrings", new TwoArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue, LuaValue luaValue1) {
                return Vstrings(luaValue,luaValue1);
            }
        });
        bd.put("Define", new TwoArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue, LuaValue luaValue1) {
                return Define(luaValue,luaValue1,symtable);
            }
        });
        bd.put("Alias", new TwoArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue, LuaValue luaValue1) {
                return Alias(luaValue,luaValue1,decaytable);
            }
        });
        bd.put("ChargeConj", new TwoArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue, LuaValue luaValue1) {
                return ChargeConj(luaValue,luaValue1);
            }
        });
        bd.put("ModelAlias", new ThreeArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue, LuaValue luaValue1, LuaValue luaValue2) {
                return ModelAlias(luaValue,luaValue1,luaValue2,modelAliases);
            }
        });
        bd.put("SND", new OneArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue) {
                return changeLStype(luaValue,"SND");
            }
        });
        bd.put("FLATTE", new OneArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue) {
                return changeLStype(luaValue,"FLATTE");
            }
        });
        bd.put("sigma_E791", new OneArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue) {
                return changeLStype(luaValue,"sigma_E791");
            }
        });
        bd.put("sigma_PKU", new OneArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue) {
                return changeLStype(luaValue,"sigma_PKU");
            }
        });
        bd.put("sigma_ZB", new OneArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue) {
                return changeLStype(luaValue,"sigma_ZB");
            }
        });
        bd.put("CDecay", new OneArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue) {
                return CDecay(luaValue,decaytable);
            }
        });
        bd.put("Decay", new TwoArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue, LuaValue luaValue1) {
                return Decay(luaValue,luaValue1,modellist,modelAliases,decaytable,symtable);
            }
        });
        bd.put("SetLineshapePW", new OneArgFunction() {
            @Override
            public LuaValue call(LuaValue luaValue) {
                return SetLineShapePW(luaValue);
            }
        });
        cs.eval(bd);
    }

    private double checkGetDouble(LuaValue val){
        if (val.isnumber()){
            return val.todouble();
        }
        throw new RuntimeException(val.toString()+" is not a double value");
    }

    private String checkGetString(LuaValue val){
        if (val.isstring()){
            return val.tojstring();
        }
        throw new RuntimeException(val.toString()+" is not a String value");
    }

    private int checkGetInt(LuaValue val){
        if(val.isnumber()){
            return val.toint();
        }
        throw new RuntimeException(val.toString()+" is not a numeric value");
    }

    public EvtId evtIdFromStdHep(int stdhep){
        for(EvtPartProp prop:partlist){
            if(prop.stdhep==stdhep){
                return prop.id;
            }
        }
        return EvtId.defaultId;
    }

    public void alias(EvtId num,String newname){
        alias(num.getId(),newname);
    }

    public void alias(int num,String newname){
        //        if ( firstAlias < partlist.size() ) {
//            for(i=firstAlias;i<partlist.size();i--){
//                if (newname.equals(partlist.get(i).name)){
//                    return;
//                }
//            }
//        } else{
//            firstAlias=partlist.size();
//        }
        for(EvtPartProp prop:partlist){
            if (newname.equals(prop.name)){
                return;
            }
        }
        partlist.add(partlist.get(num).duplicate());
        int entry=partlist.size()-1;
        partlist.get(entry).name=newname;
        if (!particleNameLookup.containsKey(newname)){
            particleNameLookup.put(newname,entry);
            partlist.get(entry).id=new EvtId(num,entry);
            partlist.get(entry).idchgconj=EvtId.defaultId;
        }
    }

    public void aliasChgConj(EvtId a,EvtId abar){
        EvtId nid1=new EvtId(a.getId(),a.getId()),nid2=new EvtId(abar.getId(),abar.getId());
        if(!nid2.equals(chargeConj(nid1))){
            throw new RuntimeException();
        }
        partlist.get(a.getAlias()).idchgconj=abar;
        partlist.get(abar.getAlias()).idchgconj=a;
    }

    public EvtId chargeConj(EvtId id){
        EvtId idchg=partlist.get(id.getAlias()).idchgconj;

        if (!idchg.equals(EvtId.defaultId)) {
            return idchg;
        }

        if (id.getId()!=id.getAlias()){
            EvtId nid=new EvtId(id.getId(),id.getId());
            if (nid.equals(chargeConj(nid))){
                partlist.get(id.getAlias()).idchgconj=id;
                return id;
            }
        }

        if (id.getAlias()!=id.getId()) {
            throw new RuntimeException();
        }
        int i;
        for (i=0;i<partlist.size();i++){
            EvtPartProp prop1=partlist.get(i),prop2=partlist.get(id.getId());
            if (prop1.stdhep==-prop2.stdhep){
                prop2.idchgconj=prop1.id;
                return prop1.id;
            }
        }
        partlist.get(id.getId()).idchgconj=id;
        return id;
    }

    private LuaValue pdtadd(LuaValue luaValue) {
        if (luaValue.istable()){
            LuaTable table=(LuaTable)luaValue;
            EvtPartProp tmp=new EvtPartProp();
            String pname=checkGetString(table.get(3));
            tmp.name=pname;
            int stdhepid=checkGetInt(table.get(4));
            double mass=checkGetDouble(table.get(5)),pwidth=checkGetDouble(table.get(6)),pmaxwidth=checkGetDouble(table.get(7));
            int chg3=checkGetInt(table.get(8)),spin2=checkGetInt(table.get(9));
            double ctau=checkGetDouble(table.get(10));
            int lundkc=checkGetInt(table.get(11));
            switch (spin2){
                case 0:
                    tmp.spintype=EvtSpinType.SpinType.SCALAR;
                    break;
                case 1:
                    tmp.spintype=mass<0.0001?EvtSpinType.SpinType.NEUTRINO: EvtSpinType.SpinType.DIRAC;
                    break;
                case 2:
                    tmp.spintype=mass<0.0001? EvtSpinType.SpinType.PHOTON: EvtSpinType.SpinType.VECTOR;
                    break;
                case 3:
                    tmp.spintype= EvtSpinType.SpinType.RARITASCHWINGER;
                    break;
                case 4:
                    tmp.spintype= EvtSpinType.SpinType.TENSOR;
                    break;
                case 5:
                    tmp.spintype= EvtSpinType.SpinType.SPIN5HALF;
                    break;
                case 6:
                    tmp.spintype= EvtSpinType.SpinType.SPIN3;
                    break;
                case 7:
                    tmp.spintype=EvtSpinType.SpinType.SPIN7HALF;
                    break;
                case 8:
                    tmp.spintype= EvtSpinType.SpinType.SPIN4;
                    break;
                default:
                    tmp.spintype= EvtSpinType.SpinType.SCALAR;
            }
            if ("string".equals(pname)){
                tmp.spintype= EvtSpinType.SpinType.STRING;
            }else if("vpho".equals(pname)){
                tmp.spintype= EvtSpinType.SpinType.VECTOR;
            }
            tmp.id=new EvtId(nentries);
            tmp.idchgconj=EvtId.defaultId;
            tmp.stdhep=stdhepid;
            tmp.lundkc=lundkc;
            if (particleNameLookup.containsKey(pname)){
                return LuaValue.error(pname+" already exists");
            }
            particleNameLookup.put(pname,nentries);
            tmp.ctau=ctau;
            tmp.chg3=chg3;
            tmp.lineShape=new EvtAbsLineShape(mass,pwidth,pmaxwidth,tmp.spintype);
            partlist.add(tmp);
            nentries++;
            return LuaValue.NIL;
        }
        return LuaValue.error("not a table");
    }

    public int chg3(EvtId i){
        return partlist.get(i.getId()).chg3;
    }

    public int  chg3(int i){
        return partlist.get(i).chg3;
    }

    public void setPWForDecay(EvtId i,int spin,EvtId d1,EvtId d2){
        partlist.get(i.getId()).lineShape.setPWForDecay(spin,d1,d2);
    }
}
